/*
 * @version: 1.0
 * @Author: zhl
 * @Date: 2021-09-01 15:38:43
 * @LastEditors: zhl
 * @LastEditTime: 2022-04-29 10:27:11
 * @Description: file content
 */
#include "GET-Response.h"
#include "dlt698_global.h"
#include "common.h"
#include "Data.h"
#include "HandleData.h"


GetResponse GetResponse::c_instance;

GetResponse::GetResponse(){

}

GetResponse::~GetResponse(){

}
//
GetResponse &GetResponse::getInstance(){
    return c_instance;
}

int GetResponse::parse_response(int64_t dev_id, uint8_t *apdu, int len, std::list<Data> &result){
    if((NULL == apdu) || (1 > len)){
        return -1;
    }
    //
    APDU_FUNC_TYPE ftype = *((APDU_FUNC_TYPE*)apdu);
    CLogger::getInstance()->log_i("APDU_FUNC_TYPE:%d", ftype);
    if(ftype == GET_RESPONSE_NORMAL_LIST){
        return parse_response_normal_list(dev_id, apdu+sizeof(APDU_FUNC_TYPE)+sizeof(PIID_TYPE), len-sizeof(APDU_FUNC_TYPE)-sizeof(PIID_TYPE), result);
    }else if(ftype == GET_RESPONSE_NORMAL){
        return parse_response_normal(dev_id, apdu+sizeof(APDU_FUNC_TYPE)+sizeof(PIID_TYPE), len-sizeof(APDU_FUNC_TYPE)-sizeof(PIID_TYPE), result);
    }else if(ftype == GET_RESPONSE_NEXT){
        return parse_response_next(dev_id, apdu+sizeof(APDU_FUNC_TYPE)+sizeof(PIID_TYPE), len-sizeof(APDU_FUNC_TYPE)-sizeof(PIID_TYPE), result);
    }
    return 0;
}
//代码可优化
int GetResponse::parse_error_response(int64_t dev_id, uint8_t *apdu, int len){
    if((NULL == apdu) || (4 > len)){
        return -1;
    }

    uint8_t code = *(uint8_t*)(apdu+sizeof(PIID_TYPE));
    if(1 == code){
        CLogger::getInstance()->log_w("APDU 无法解析: (%d)", code);
    } else if(2 == code){
        CLogger::getInstance()->log_w("服务不支持: (%d)", code);
    } else {
        CLogger::getInstance()->log_w("未知异常: (%d)", code);
    }
    return 0;
}

int GetResponse::parse_response_normal(int64_t dev_id, uint8_t *data, int len, std::list<Data> &result){
    return parse_data(dev_id, data, len, result);
}

int GetResponse::parse_response_normal_list(int64_t dev_id, uint8_t *data, int len, std::list<Data> &result){
    DATA_SIZE_TYPE n = *((DATA_SIZE_TYPE *)data);
    int offset = sizeof(DATA_SIZE_TYPE);
    for(int i = 0; i < n; i++){
        if(offset == len){
            return 0;
        }
        if(offset > len){
            return -1;
        }
         
        int ret = parse_response_normal(dev_id, data+offset, len-offset, result);
        
        if(0 < ret){
            offset += ret;
        }
    }
    return offset;
}
//
int GetResponse::parse_response_next(int64_t dev_id, uint8_t *data, int len, std::list<Data> &result){
    return parse_response_normal_list(dev_id, data+sizeof(uint8_t)+sizeof(SEPARATE_FRAME), len-sizeof(uint8_t)-sizeof(SEPARATE_FRAME), result);
}

int GetResponse::get_items(uint8_t *data, int len, int &offset, Data &value){

    if((NULL == data) || (1 > len) || (offset >= len)){
        return -1;
    }
    if((NULL == dlt698_global_conf) || (nullptr == dlt698_global_conf->get_dlt698_data_type())){
        return -1;
    }
    //
    DATA_CODE_TYPE code = *((DATA_CODE_TYPE *)(data+offset));
    std::unordered_map<int64_t, DLT698_DATA_TYPE>::iterator it = dlt698_global_conf->get_dlt698_data_type()->find(code);
    if(it == dlt698_global_conf->get_dlt698_data_type()->end()){
        return -1;
    }
    offset += sizeof(DATA_CODE_TYPE);
    std::string dt = "";
    dt.resize(32);
    transform(it->second.data_type.begin(), it->second.data_type.end(), dt.begin(), ::toupper);
    if(0 == strcmp(dt.c_str(), "BASE")){
        uint8_t *p = (uint8_t *)malloc(it->second.size);
        memcpy(p, data+offset, it->second.size);
        value.push(std::make_pair(it->second.size, p)); 
        offset += it->second.size;
    }else if(0 == strcmp(dt.c_str(), "EQUAL")){
        std::unordered_map<int64_t, DLT698_DATA_TYPE>::iterator tit = dlt698_global_conf->get_dlt698_data_type()->find(it->second.equal_system_data_type);
        if(tit == dlt698_global_conf->get_dlt698_data_type()->end()){
            return -1;
        }
        //uint8_t *p = (uint8_t *)(data+offset);
        int size = tit->second.size;
        if(0 < it->second.size){
            size = size * it->second.size;
        }
        uint8_t *p = (uint8_t *)malloc(size);
        memcpy(p, data+offset, size);
        value.push(std::make_pair(size, p));
        offset  += size;
    }else if((0 == strcmp(dt.c_str(), "ARRAY")) || (0 == strcmp(dt.c_str(), "STRUCTURE"))){
        DATA_SIZE_TYPE n = *((DATA_SIZE_TYPE *)(data+offset));
        offset += sizeof(DATA_SIZE_TYPE);
        for(int i = 0; i < n; i++){
            get_items(data, len, offset, value);
        }
    }else if(0 == strcmp(dt.c_str(), "SEQUENCE")){
    }else{
        offset = -1;
    }    
    return offset;
}
//
int GetResponse::parse_data(int64_t dev_id, uint8_t *data, int len, std::list<Data> &result){
    if((NULL == data) || (1 > len)){
        return -1;
    }
    Data d;
    d.c_dev_id = dev_id;
    memcpy(d.c_oad, data, sizeof(OAD_TYPE));
    CLogger::getInstance()->log_i("OAD: %02X %02X %02X %02X", d.c_oad[0], d.c_oad[1], d.c_oad[2], d.c_oad[3]);
    int offset = sizeof(OAD_TYPE);
    
    RESULT_TYPE ret = *((RESULT_TYPE *)(data+offset));
    offset += sizeof(RESULT_TYPE);
    if(0x01 == ret){
        ret = get_items(data, len, offset, d);
        result.push_back(d);
        // HandleData::getInstance().handle(d);
        return ret; 
    }else{
        //读取异常
        return -1;
    }
}